use std::collections::{HashMap};
use std::net::{TcpStream, SocketAddr};
use std::time::Duration;

use mio::{Poll, Events, Token, Ready, PollOpt, net::TcpListener};
use ws::{HandshakeError, Error, Message, WebSocket};
use ws::handshake::HandshakeRole;
use ws;

use json;
use json::{Value};

use game;
use game::chess::ChessPlayer;


///连接id计算
static mut CONNECTION_ID: u32 = 1000000000;

fn new_connection_id() -> u32{
    unsafe {
        if CONNECTION_ID > 999999998{
            CONNECTION_ID = 100000000;
        }
        CONNECTION_ID = CONNECTION_ID + 1;
        CONNECTION_ID
    }
}

pub struct GameServer{
    run: bool,
    token: Token,
    listener: TcpListener,
    poll: Poll,
    events: Events,
    streams: HashMap<u32, WebSocket<TcpStream>>,
    map: HashMap<u32, u32>
}

impl GameServer{
    pub fn new(addr: SocketAddr) -> GameServer{
        let server = TcpListener::bind(&addr).unwrap();
        info!("Server start on address: {:?}", addr);
        let poll = Poll::new().unwrap();
        let mut events = Events::with_capacity(64);
        let token = Token(0);
        poll.register(&server, token, Ready::readable(), PollOpt::edge()).unwrap();
        let streams = HashMap::<u32, WebSocket<TcpStream>>::new();
        let mut map = HashMap::<u32, u32>::new();
        GameServer{
            run: true,
            token,
            listener: server,
            poll,
            events,
            streams,
            map
        }
    }

    pub fn is_running(&self) -> bool{
        self.run
    }

    pub fn handle(&mut self) -> Vec<ChessPlayer>{
        info!("Server handler run.........");
        let duration = Some(Duration::from_millis(100));
        self.poll.poll(&mut self.events, duration).unwrap();
        for event in self.events.iter() {
            match event.token() {
                Token(0) => {
                    let accept = self.listener.accept_std();
                    match accept {
                        Ok((stream, _address)) => {
                            let conn = ws::accept(stream).map_err(must_not_block);
                            match conn {
                                Ok(mut socket) => {
                                    let id = new_connection_id();
                                    info!("New connection come in, id = {}", id);
                                    let message = json!({"code": 0, "status": "sign", "id": id});
                                    socket.write_message(Message::from(message.to_string()));
                                    self.streams.insert(id, socket);
                                },
                                Err(e) => error!("Cannot accept connection: {:?}", e),
                            }
                        },
                        Err(e) => info!("Accept connection error! {}", e),
                    };
                },
                _ => unreachable!(),
            };
        }
        info!("Complete accept user connect.");
        //存放需要移除的连接的id
        let mut remove = Vec::<u32>::new();
        for (key, socket) in self.streams.iter_mut(){
            info!("Read from stream: {}", key);
            let ret = socket.read_message();
            match ret {
                Ok(message) => {
                    match message {
                        Message::Text(data) => {
                            trace!("Receive message from client: {}, content: {:?}", key, data);
                            let result = handle_message(data.as_str());
                            match result {
                                game::Result::Ok(id) => {self.map.insert(*key, id);},
                                game::Result::Error(code) => {
                                    let answer = json!({"code": code});
                                    socket.write_message(Message::from(answer.to_string()));
                                },
                            }
                        },
                        Message::Binary(bytes) => {
                            unsafe {
                                let data = String::from_utf8_unchecked(bytes);
                                trace!("Receive message from client: {}, content: {:?}", key, data);
                                let result = handle_message(data.as_str());
                                match result {
                                    game::Result::Ok(id) => {self.map.insert(*key, id);},
                                    game::Result::Error(code) => {
                                        let answer = json!({"code": code});
                                        socket.write_message(Message::from(answer.to_string()));
                                    },
                                }
                            }
                        }
                        Message::Ping(_) |
                        Message::Pong(_) => ()
                    }
                },
                Err(e) => {
                    error!("Receive message from connection error. {}", e);
                    match e {
                        Error::ConnectionClosed(_) => {remove.push(*key);},
                        _ => ()
                    }
                }
            }
        }
        info!("Read player match message complete.");
        let mut players = Vec::<ChessPlayer>::new();
        for (id, user) in &self.map{
            match self.streams.remove(&id) {
                Some(socket) => {
                    let player = ChessPlayer::new(*user, socket);
                    players.push(player);
                },
                None => ()
            }
            remove.push(*id);
        }
        for i in remove{
            self.streams.remove(&i);
            self.map.remove(&i);
        }
        info!("Receive new player match complete.");
        players
    }
}

fn must_not_block<Role: HandshakeRole>(err: HandshakeError<Role>) -> Error {
    match err {
        HandshakeError::Interrupted(_) => panic!("Bug: blocking socket would block"),
        HandshakeError::Failure(f) => f,
    }
}

///用户网络消息处理
pub fn handle_message(data: &str) -> game::Result{
    trace!("Received an message: {}", data);

    let value = json::from_str(data).unwrap_or(Value::Null);
    if let Value::Null = value{
        return game::Result::Error(101);
    }

    let error = game::Result::Error(102);
    let c = value.pointer("/user").unwrap_or(&Value::Null);

    if let &Value::Null = c{
        return game::Result::Error(102);
    }
    let code = c.as_u64().unwrap_or(0);
    let user = code as u32;
    if 0 < user{
        return game::Result::Ok(user);
    }
    return game::Result::Error(102);
}